/*
 * File:   Scanner.cpp
 * Author: ScaV
 *
 * Created on October 18, 2011, 6:22 PM
 */

#include "scanner.h"
#include "utility.h"
#include <cstdlib>
#include <ctype.h>
#include <cstring>

scanner::scanner(const char *fname) {
	states = new bool[N];
	infile.open(fname, std::fstream::in);
	if (!infile.is_open())
		throw "Can't open scanner input file!";
	line = 1;
}

scanner::~scanner() {
	if (infile.is_open())
		infile.close();
	delete[] states;
}

lexeme *scanner::getNextLex() {
	lexeme *lx;
	char ch, rem = '\0';
	LEX_TYPE ltype = LEX_UNKNOWN;
	bool *nextstates;
	if (!str.empty())
		rem = str.back();
	reset();
	while (1) {
		if (!rem) {
			ch = infile.get();
		} else {
			ch = rem;
			rem = '\0';
		}
		if (!(nextstates = getNextStates(ch)))
			throw "Can't alloc nextstates!";
		free(states);
		states = nextstates;
		if (isAlive()) {
			ltype = checkFinal();
			str.push_back(ch);
		} else {
			if (!str.empty() && (isSeparator(ch) || isLanguageSeparator(str.back()) || infile.eof())) {
				lx = new lexeme;
				lx->setType(ltype);
				lx->setLine(line);
				lx->setName(str);
				str.push_back(ch);
				return lx;
			} else if (!isSeparator(ch)) {
				ltype = LEX_UNKNOWN;
				str.push_back(ch);
			} else if (str.empty()) { reset(); }
		}
		if (infile.eof()) {
			lx = new lexeme;
			lx->setLine(line);
			lx->setType(LEX_END);
			return lx;
		}
		if (ch == '\n')
			line++;
	}
}

bool *scanner::getNextStates(char ch) {
	bool *nextstate;
	nextstate = new bool[N];
	if (nextstate) {
		memset(nextstate, 0, N * sizeof (bool));
		if (isalpha(ch)) {
			nextstate[1] = states[0] && ch == 'i';
			nextstate[2] = states[1] && ch == 'n';
			nextstate[3] = states[2] && ch == 't';

			nextstate[4] = states[0] && ch == 'd';
			nextstate[5] = states[4] && ch == 'o';
			nextstate[6] = states[5] && ch == 'u';
			nextstate[7] = states[6] && ch == 'b';
			nextstate[8] = states[7] && ch == 'l';
			nextstate[9] = states[8] && ch == 'e';

			nextstate[10] = states[0] && ch == 'r';
			nextstate[11] = states[10] && ch == 'e';
			nextstate[12] = states[11] && ch == 't';
			nextstate[13] = states[12] && ch == 'u';
			nextstate[14] = states[13] && ch == 'r';
			nextstate[15] = states[14] && ch == 'n';

			nextstate[16] = states[0] && ch == 'i';
			nextstate[17] = states[16] && ch == 't';
			nextstate[18] = states[17] && ch == 'o';
			nextstate[19] = states[18] && ch == 'd';

			nextstate[20] = states[0] && ch == 'd';
			nextstate[21] = states[20] && ch == 't';
			nextstate[22] = states[21] && ch == 'o';
			nextstate[23] = states[22] && ch == 'i';

			nextstate[24] = states[0] || states[24];
			nextstate[28] = states[27] && ch == 'd';
		}
		if (isdigit(ch)) {
			nextstate[24] = states[24];
			nextstate[25] = states[0] && ch == '0';
			nextstate[27] = states[26] || states[27];
			nextstate[31] = states[28] || states[29]|| states[30] || states[31];
			nextstate[32] = states[0] || states[32];
		}
		if(ch == '.') {
			nextstate[26] = states[25];
			nextstate[30] = states[0];
			nextstate[31] = states[32];
		}
		nextstate[29] = states[28] && (ch == '+' || ch == '-');
		nextstate[33] = states[0] && isLanguageSeparator(ch);
	}
	return nextstate;
}

LEX_TYPE scanner::checkFinal() {
	if (states[3] || states[9] || states[15] || states[19] || states[23])
		return LEX_KEYWORD;
	if (states[24])
		return LEX_IDENTIFICATOR;
	if (states[31] || states[32])
		return LEX_CONSTANT;
	if (states[33])
		return LEX_SEPARATOR;
	return LEX_UNKNOWN;
}

bool scanner::isAlive() {
	for (int i = 0; i < N; ++i) {
		if (states[i])
			return true;
	}
	return false;
}

void scanner::reset() {
	str.clear();
	*states = true;
	memset(states + 1, false, (N - 1) * sizeof (bool));
}

